from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponse
from django.db.models import Q
from django.urls import reverse
from datetime import datetime
from main.models import User, Room, Booking, Bill, Feedback
import csv
from io import StringIO
from functools import wraps


def user_login(request):
    """用户登录 - 使用浏览器cookie存储用户信息"""
    if request.method == 'POST':
        # 获取表单数据并进行基本验证
        username = request.POST.get('username', '').strip()
        password = request.POST.get('password', '')
        
        # 验证输入不为空
        if not username or not password:
            messages.error(request, '用户名和密码不能为空')
            return render(request, 'user/login.html')
        
        # 直接查询用户，不使用authenticate函数
        try:
            user = User.objects.get(username=username)
            # 直接比较密码（不推荐生产环境，仅用于修复当前问题）
            if user.password == password:
                # 根据用户角色确定重定向目标
                if user.role == 'admin':
                    response = redirect('hotel_admin:dashboard')
                else:
                    response = redirect('user:dashboard')
                
                # 使用浏览器cookie存储用户ID和用户名，设置过期时间为1天
                # 使用httponly=True增强安全性，防止XSS攻击
                response.set_cookie('user_id', str(user.id), max_age=86400, httponly=True, samesite='Lax')
                response.set_cookie('username', user.username, max_age=86400, samesite='Lax')
                
                # 记录登录成功信息
                messages.success(request, f'欢迎回来，{user.username}！')
                return response
            else:
                messages.error(request, '用户名或密码错误')
        except User.DoesNotExist:
            messages.error(request, '用户名或密码错误')
    
    return render(request, 'user/login.html')


def user_register(request):
    """用户注册"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        email = request.POST.get('email')
        phone = request.POST.get('phone')
        
        try:
            # 使用create_user方法创建用户，会自动处理密码哈希
            user = User.objects.create_user(
                username=username,
                password=password,
                email=email,
                phone=phone,
                role='user'
            )
            messages.success(request, '注册成功,请登录')
            return redirect('user:user_login')
        except Exception as e:
            messages.error(request, f'注册失败: {str(e)}')
    
    return render(request, 'user/register.html')


# 不使用Django内置的login_required装饰器，使用自定义的基于cookie的装饰器
def user_required(view_func):
    """自定义用户登录验证装饰器 - 基于浏览器cookie"""
    @wraps(view_func)
    def wrapper(request, *args, **kwargs):
        # 检查cookie中是否存在user_id
        user_id = request.COOKIES.get('user_id')
        # 验证user_id不为空且为有效数字
        if not user_id or not user_id.isdigit():
            messages.error(request, '请先登录')
            return redirect('user:user_login')
        
        # 验证用户是否仍然存在
        try:
            user = User.objects.get(id=int(user_id))
            # 将用户对象存入request对象，方便后续视图使用
            request.user = user
        except User.DoesNotExist:
            # 如果用户不存在，清除cookie并重定向到登录页
            response = redirect('user:user_login')
            response.delete_cookie('user_id')
            response.delete_cookie('username')
            messages.error(request, '用户不存在或已被删除')
            return response
            
        return view_func(request, *args, **kwargs)
    return wrapper

@user_required
def dashboard(request):
    """用户仪表板"""
    # 直接从request.user获取用户对象，避免重复查询数据库
    user = request.user
    
    # 获取用户预订信息
    bookings = Booking.objects.filter(
        user_id=user.id
    ).select_related('room').order_by('-created_at')
    
    # 获取用户账单
    bills = Bill.objects.filter(
        booking__user_id=user.id
    ).select_related('booking', 'booking__room').order_by('-created_at')
    
    # 获取用户反馈
    feedbacks = Feedback.objects.filter(
        user_id=user.id
    ).order_by('-created_at')
    
    return render(request, 'user/dashboard.html', {
        'user': user,
        'bookings': bookings,
        'bills': bills,
        'feedbacks': feedbacks
    })


@user_required
def search_rooms(request):
    """房间搜索和预订统一视图 - 优化版"""
    from datetime import datetime, timedelta
    from django.db.models import Q
    
    # 处理POST请求 - 提交预订
    if request.method == 'POST':
        return handle_booking_submission(request)
    
    # 处理GET请求 - 显示搜索结果
    # 获取并验证搜索参数
    keyword = request.GET.get('keyword', '').strip()
    price_range = request.GET.get('price_range', 'all')
    room_type = request.GET.get('room_type', 'all')
    capacity = request.GET.get('capacity', 'all')
    sort_by = request.GET.get('sort_by', 'default')
    check_in = request.GET.get('check_in', '').strip()
    check_out = request.GET.get('check_out', '').strip()
    guests = request.GET.get('guests', '').strip()
    
    # 日期验证和转换
    check_in_date, check_out_date = validate_dates(check_in, check_out)
    
    # 如果日期无效，清空字符串
    if not check_in_date or not check_out_date:
        check_in = ''
        check_out = ''
    
    # 构建查询集 - 只获取可用房间
    query = Room.objects.filter(status='available')
    
    # 如果提供了日期范围，过滤出在该日期范围内可用的房间
    if check_in_date and check_out_date:
        conflicting_room_ids = get_conflicting_rooms(check_in_date, check_out_date)
        if conflicting_room_ids:
            query = query.exclude(id__in=conflicting_room_ids)
    
    # 应用筛选条件
    query = apply_search_filters(query, keyword, price_range, room_type, capacity, guests)
    
    # 应用排序
    rooms = apply_sorting(query, sort_by)
    
    # 预计算房间信息
    room_data = prepare_room_data(rooms, check_in_date, check_out_date)
    
    # 构建搜索参数字典
    search_params = {
        'keyword': keyword,
        'price_range': price_range,
        'room_type': room_type,
        'capacity': capacity,
        'sort_by': sort_by,
        'check_in': check_in,
        'check_out': check_out,
        'guests': guests
    }
    
    # 添加统计信息
    total_available = Room.objects.filter(status='available').count()
    total_matched = len(room_data)
    
    # 添加默认日期建议
    today = datetime.now().date()
    default_check_in = check_in if check_in else (today + timedelta(days=1)).strftime('%Y-%m-%d')
    default_check_out = check_out if check_out else (today + timedelta(days=2)).strftime('%Y-%m-%d')
    
    # 检查是否有预选房间
    preselected_room_id = request.GET.get('room_id')
    preselected_room = None
    if preselected_room_id:
        try:
            preselected_room = Room.objects.get(id=preselected_room_id, status='available')
        except Room.DoesNotExist:
            messages.warning(request, '预选房间不存在或已被预订')
    
    return render(request, 'user/book.html', {
        'room_data': room_data,
        'search_params': search_params,
        'total_available': total_available,
        'total_matched': total_matched,
        'default_check_in': default_check_in,
        'default_check_out': default_check_out,
        'preselected_room': preselected_room
    })


def validate_dates(check_in, check_out):
    """验证并转换日期"""
    from datetime import datetime
    
    check_in_date = None
    check_out_date = None
    
    try:
        if check_in:
            check_in_date = datetime.strptime(check_in, '%Y-%m-%d').date()
        if check_out:
            check_out_date = datetime.strptime(check_out, '%Y-%m-%d').date()
        
        # 验证日期有效性
        today = datetime.now().date()
        if check_in_date and check_in_date < today:
            check_in_date = None
            check_out_date = None
        elif check_in_date and check_out_date and check_in_date >= check_out_date:
            check_in_date = None
            check_out_date = None
    except ValueError:
        check_in_date = None
        check_out_date = None
    
    return check_in_date, check_out_date


def get_conflicting_rooms(check_in_date, check_out_date):
    """获取在指定日期范围内已被预订的房间ID列表"""
    from django.db.models import Q
    
    return Booking.objects.filter(
        Q(check_in__lt=check_out_date) & Q(check_out__gt=check_in_date) &
        Q(status__in=['pending', 'confirmed', 'paid', 'checked_in'])
    ).values_list('room_id', flat=True)


def apply_search_filters(query, keyword, price_range, room_type, capacity, guests):
    """应用搜索筛选条件"""
    from django.db.models import Q
    
    # 价格和容量筛选器字典
    price_filters = {
        '0-200': {'price__gte': 0, 'price__lte': 200},
        '200-500': {'price__gte': 200, 'price__lte': 500},
        '500-1000': {'price__gte': 500, 'price__lte': 1000},
        '1000+': {'price__gte': 1000}
    }
    
    capacity_filters = {
        '1': {'capacity': 1},
        '2': {'capacity': 2},
        '3': {'capacity__gte': 3, 'capacity__lte': 4},
        '5+': {'capacity__gte': 5}
    }
    
    # 关键词搜索
    if keyword:
        query = query.filter(
            Q(name__icontains=keyword) | 
            Q(description__icontains=keyword) |
            Q(room_type__icontains=keyword)
        )
    
    # 价格范围
    if price_range != 'all' and price_range in price_filters:
        query = query.filter(**price_filters[price_range])
    
    # 房间类型
    if room_type != 'all':
        query = query.filter(room_type=room_type)
    
    # 容纳人数
    if capacity != 'all' and capacity in capacity_filters:
        query = query.filter(**capacity_filters[capacity])
    
    # 入住人数
    if guests.isdigit():
        guest_count = int(guests)
        if guest_count > 0:
            query = query.filter(capacity__gte=guest_count)
    
    return query


def apply_sorting(query, sort_by):
    """应用排序规则"""
    sort_options = {
        'price_asc': ['price'],
        'price_desc': ['-price'],
        'popularity': ['-count'],
        'capacity_asc': ['capacity'],
        'capacity_desc': ['-capacity'],
        'default': ['-count', 'price']
    }
    
    if sort_by in sort_options:
        return query.order_by(*sort_options[sort_by])
    return query.order_by('-count', 'price')


def prepare_room_data(rooms, check_in_date, check_out_date):
    """准备房间数据，包含价格计算"""
    room_data = []
    for room in rooms:
        room_info = {
            'room': room,
            'price_per_night': room.price,
            'total_price': None,
            'nights': 0
        }
        # 计算总价和晚数
        if check_in_date and check_out_date:
            nights = (check_out_date - check_in_date).days
            if nights > 0:
                room_info['nights'] = nights
                room_info['total_price'] = float(room.price) * nights
        room_data.append(room_info)
    return room_data


def handle_booking_submission(request):
    """处理预订提交"""
    from datetime import datetime
    
    room_id = request.POST.get('room_id')
    check_in = request.POST.get('check_in', '').strip()
    check_out = request.POST.get('check_out', '').strip()
    guests = request.POST.get('guests', '').strip()
    
    # 验证必填字段
    if not all([room_id, check_in, check_out, guests]):
        messages.error(request, '请填写完整的预订信息')
        return redirect('user:search_rooms')
    
    try:
        # 验证房间
        room = Room.objects.get(id=room_id, status='available')
        
        # 验证日期
        check_in_date = datetime.strptime(check_in, '%Y-%m-%d').date()
        check_out_date = datetime.strptime(check_out, '%Y-%m-%d').date()
        today = datetime.now().date()
        
        if check_in_date < today:
            messages.error(request, '入住日期不能早于今天')
            return redirect('user:search_rooms')
        
        if check_out_date <= check_in_date:
            messages.error(request, '退房日期必须晚于入住日期')
            return redirect('user:search_rooms')
        
        # 验证人数
        guest_count = int(guests)
        if guest_count <= 0:
            messages.error(request, '入住人数必须大于0')
            return redirect('user:search_rooms')
        
        if guest_count > room.capacity:
            messages.error(request, f'入住人数不能超过房间容量({room.capacity}人)')
            return redirect('user:search_rooms')
        
        # 检查房间在选定日期是否可用
        conflicting_bookings = Booking.objects.filter(
            room=room,
            status__in=['pending', 'confirmed', 'paid', 'checked_in'],
            check_in__lt=check_out_date,
            check_out__gt=check_in_date
        )
        
        if conflicting_bookings.exists():
            messages.error(request, '该房间在选定日期已被预订，请选择其他日期或房间')
            return redirect('user:search_rooms')
        
        # 计算总价
        nights = (check_out_date - check_in_date).days
        total_price = float(room.price) * nights
        
        # 创建预订
        booking = Booking.objects.create(
            user=request.user,
            room=room,
            guest_name=request.user.username,
            guest_phone=request.user.phone or '',
            guest_email=request.user.email,
            check_in=check_in_date,
            check_out=check_out_date,
            guests=guest_count,
            total_price=total_price,
            status='confirmed'
        )
        
        # 创建账单
        Bill.objects.create(
            booking=booking,
            amount=total_price,
            status='pending'
        )
        
        # 更新房间预订计数
        room.count += 1
        room.save()
        
        messages.success(request, f'预订成功！房间: {room.name}，入住日期: {check_in}，共{nights}晚，总计: ¥{total_price}')
        return redirect('user:dashboard')
        
    except Room.DoesNotExist:
        messages.error(request, '所选房间不存在或已被预订')
        return redirect('user:search_rooms')
    except ValueError as e:
        messages.error(request, f'输入数据格式错误: {str(e)}')
        return redirect('user:search_rooms')
    except Exception as e:
        messages.error(request, f'预订失败: {str(e)}')
        return redirect('user:search_rooms')



# book_room视图已合并到search_rooms中，保留此函数仅为兼容性重定向
@user_required
def book_room(request):
    """房间预订 - 重定向到搜索页面"""
    # 如果有room_id参数，传递给search_rooms
    room_id = request.GET.get('room_id')
    if room_id:
        return redirect(f"{reverse('user:search_rooms')}?room_id={room_id}")
    return redirect('user:search_rooms')


@user_required
def cancel_booking(request, booking_id):
    """取消预订"""
    booking = get_object_or_404(
        Booking,
        id=booking_id,
        user=request.user
    )
    
    # 更新预订状态为已取消
    booking.status = 'cancelled'
    booking.save()
    
    # 将房间状态改回可预订
    booking.room.status = 'available'
    booking.room.save()
    
    messages.success(request, '预订已取消')
    return redirect('user:dashboard')


@user_required
def pay_bill(request, bill_id):
    """支付账单"""
    bill = get_object_or_404(
        Bill,
        id=bill_id,
        booking__user=request.user
    )
    
    bill.status = 'paid'
    bill.paid_at = datetime.now()
    bill.save()
    
    messages.success(request, '支付成功!')
    return redirect('user:dashboard')


@user_required
def submit_feedback(request):
    """提交问题反馈"""
    if request.method == 'POST':
        title = request.POST.get('title')
        description = request.POST.get('description')
        
        Feedback.objects.create(
            user=request.user,
            title=title,
            description=description
        )
        
        messages.success(request, '问题反馈已提交')
        return redirect('user:dashboard')
    
    return render(request, 'user/feedback.html')


@user_required
def download_invoice(request, bill_id):
    """下载发票"""
    bill = get_object_or_404(
        Bill,
        id=bill_id,
        booking__user=request.user
    )
    
    # 生成CSV格式的发票
    output = StringIO()
    writer = csv.writer(output)
    
    # 写入发票内容
    writer.writerow(['酒店预订发票'])
    writer.writerow([''])
    writer.writerow(['发票编号:', f"INV-{bill.id}"])
    writer.writerow(['用户信息:', bill.booking.user.username, bill.booking.user.email])
    writer.writerow(['房间信息:', bill.booking.room.name])
    writer.writerow(['入住日期:', bill.booking.check_in])
    writer.writerow(['退房日期:', bill.booking.check_out])
    writer.writerow(['总金额:', f"¥{bill.amount}"])
    writer.writerow(['支付状态:', '已支付' if bill.status == 'paid' else '未支付'])
    writer.writerow(['支付时间:', bill.paid_at if bill.paid_at else '未支付'])
    
    # 准备下载响应
    output.seek(0)
    response = HttpResponse(output.getvalue(), content_type='text/csv')
    response['Content-Disposition'] = f'attachment; filename=invoice_{bill_id}.csv'
    
    return response


@user_required
def user_logout(request):
    """用户退出登录 - 使用浏览器cookie管理"""
    # 创建响应对象
    response = redirect('index')
    # 删除cookie中的用户信息
    response.delete_cookie('user_id')
    response.delete_cookie('username')
    messages.info(request, '您已成功退出登录')
    return response
